using System;
using System.Text;
using System.Collections;
using System.Reflection;
using System.Runtime.Serialization;

using Crainiate.Data.Persistence.Cache;

namespace Crainiate.Data.Persistence
{
    [Serializable]
	public class Condition: Column, ICondition
	{
		private Comparison _comparison;
		private object _value;

        //Constructors
        public Condition(Type type, string field, object value): base(type, field)
        {
            Value = value;
            Comparison = Comparison.Equals;
        }

        public Condition(Type type, string field, object value, Comparison comparison): base(type, field)
        {
            Value = value;
            Comparison = comparison;
        }

        public Condition(PropertyInfo field, object value): base(field)
        {
            Value = value;
            Comparison = Comparison.Equals;
        }

        public Condition(PropertyInfo field, object value, Comparison comparison): base(field)
        {

            Value = value;
            Comparison = comparison;
        }

        protected Condition(SerializationInfo info, StreamingContext context): base(info, context)
        {
            _comparison = (Comparison) Enum.Parse(typeof(Comparison), info.GetString("Comparison"));
            _value = info.GetValue("Value", typeof(object));
        }

        //Properties
		public virtual Comparison Comparison
		{
			get
			{
				return _comparison;
			}
			set
			{
                //Validate that certains comparisons can be performed only on strings
                if (!typeof(string).IsAssignableFrom(PropertyInfo.PropertyType))
                {
                    if (value == Comparison.Contains || value == Comparison.StartsWith) throw new ConditionException("Contains and Starts With comparisons can only be performed on string types.");
                }
                
                _comparison = value;
			}
		}

		public virtual object Value
		{
			get
			{
				return _value;
			}
			set
			{
                Type type = value.GetType();
                if (!type.IsValueType && type != typeof(string)) throw new ConditionException("Value provided for condition is not a value type.");
				_value = value;
			}
		}

        //Overrides
        public override int GetHashCode()
        {
            StringBuilder builder = new StringBuilder();

            PropertyInfo prop = PropertyInfo;
            
            if (typeof(IView).IsAssignableFrom(prop.ReflectedType))
            {
                ReflectionCacheItem cache = Component.Instance.ReflectionCache.Lookup(prop.ReflectedType);
                prop = cache.GetOriginalProperty(prop);
            }
            
            builder.Append(prop.ToString());
            builder.Append(_comparison.ToString());
            
            return builder.ToString().GetHashCode();
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("Comparison", Convert.ToInt32(Comparison).ToString());
            info.AddValue("Value", Value);
        }
        
	}
}
